﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Widgetsphere.Generator.Models;
using Widgetsphere.Generator.ProjectItemGenerators;
using Widgetsphere.Generator.DataTransfer;
using Widgetsphere.Generator.Common.Util;
using Widgetsphere.Generator;


namespace Acme.GeneratorExtension.OverrideDTO
{
	/// <summary>
	/// This template will generate the content for the [EntityName]MetaData.cs file. This file
	/// will contain a public partial class [EntityName]MetaData. This file is 
	/// provided as a way to allow programmers to extend the generated class. 
	/// It will be generated once and never over written after that point.
	/// </summary>
	public class OverrideDTOTemplate : BaseDataTransferTemplate
	{
		private StringBuilder sb = new StringBuilder();
		private Table _currentTable;

		public OverrideDTOTemplate(ModelRoot model, Table currentTable)
		{
			_model = model;
			_currentTable = currentTable;
		}

		#region BaseClassTemplate overrides

		public override string FileName
		{
			get { return string.Format("{0}DTO.Generated.cs", _currentTable.PascalName); }
		}

		public string ParentItemName
		{
			get { return string.Format("{0}DTO.cs", _currentTable.PascalName); }
		}

		public override string FileContent
		{
			get
			{
				GenerateContent();
				return sb.ToString();
			}
		}

		#endregion

		#region GenerateContent

		private void GenerateContent()
		{
			try
			{
				this.AppendUsingStatements();
				sb.AppendLine("namespace " + DefaultNamespace);
				sb.AppendLine("{");
				this.AppendMyOverrideClass();
				sb.AppendLine("}");
			}
			catch (Exception ex)
			{
				throw;
			}
		}

		//CUSTOM OVERRIDE DO WHAT YOU WANT
		private void AppendMyOverrideClass()
		{
			try
			{
				sb.AppendLine("	/// <summary>");
				sb.AppendLine("	/// Object data transfer definition for the '" + _currentTable.DatabaseName + "' table");
				if (_currentTable.Description != "")
					sb.AppendLine("	/// " + _currentTable.Description);
				sb.AppendLine("	/// </summary>");

				sb.AppendLine("	[Serializable()]");
				sb.AppendLine("	[DataContract()]");
				if (_currentTable.ParentTable == null)
					sb.AppendLine("	public partial class " + _currentTable.PascalName + "DTO : IDTO");
				else
					sb.AppendLine("	public partial class " + _currentTable.PascalName + "DTO : " + _currentTable.ParentTable.PascalName + "DTO, IDTO");

				sb.AppendLine("	{");
				sb.AppendLine("	}");
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		#endregion

		#region namespace / objects

		public void AppendUsingStatements()
		{
			sb.AppendLine("using System;");
			sb.AppendLine("using System.Collections.Generic;");
			sb.AppendLine("using System.Linq;");
			sb.AppendLine("using System.Text;");
			sb.AppendLine("using System.Xml;");
			sb.AppendLine("using System.ComponentModel;");
			sb.AppendLine("using " + _model.CompanyName + "." + _model.ProjectName + ".DataTransfer;");
			sb.AppendLine("using System.Runtime.Serialization;");
			sb.AppendLine();
		}

		//THIS METHOD IS NOT CALLED. I ONLY PROVIDED HERE TO IDENTIFY WHAT THE ORIGINAL TEMPLATE LOOKED LIKE
		private void AppendClassCopiedFromOriginalTemplate()
		{
			try
			{
				sb.AppendLine("	/// <summary>");
				sb.AppendLine("	/// Object data transfer definition for the '" + _currentTable.DatabaseName + "' table");
				if (_currentTable.Description != "")
					sb.AppendLine("	/// " + _currentTable.Description);
				sb.AppendLine("	/// </summary>");

				sb.AppendLine("	[Serializable()]");
				sb.AppendLine("	[DataContract()]");
				if (_currentTable.ParentTable == null)
					sb.AppendLine("	public partial class " + _currentTable.PascalName + "DTO : IDTO" );
				else
					sb.AppendLine("	public partial class " + _currentTable.PascalName + "DTO : " + _currentTable.ParentTable.PascalName + "DTO, IDTO");

				sb.AppendLine("	{");

				sb.AppendLine("		#region Class Members");
				sb.AppendLine();

				IEnumerable<Column> imageColumnList = _currentTable.GetColumnsByType(System.Data.SqlDbType.Image);
				if (imageColumnList.Count() != 0)
				{
					sb.AppendLine("		#region FieldImageConstants Enumeration");
					sb.AppendLine();
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// An enumeration of this object's image type fields");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		public enum FieldImageConstants");
					sb.AppendLine("		{");
					foreach (Column column in imageColumnList)
					{
						sb.AppendLine("			 /// <summary>");
						sb.AppendLine("			 /// Field mapping for the image column '" + column.PascalName + "' property");
						sb.AppendLine("			 /// </summary>");
						sb.AppendLine("			[System.ComponentModel.Description(\"Field mapping for the image column '" + column.PascalName + "' property\")]");
						sb.AppendLine("			" + column.PascalName + ",");
					}
					sb.AppendLine("		}");
					sb.AppendLine();
					sb.AppendLine("		#endregion");
					sb.AppendLine();
				}

				sb.AppendLine("		#region FieldNameConstants Enumeration");
				sb.AppendLine();
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// An enumeration of this object's fields");
				sb.AppendLine("		/// </summary>");
				sb.AppendLine("		public " + (_currentTable.ParentTable == null ? "" : "new ") + "enum FieldNameConstants");
				sb.AppendLine("		{");
				foreach (Column column in _currentTable.GetColumnsFullHierarchy().Where(x => x.Generated))
				{
					sb.AppendLine("			 /// <summary>");
					sb.AppendLine("			 /// Field mapping for the '" + column.PascalName + "' property");
					sb.AppendLine("			 /// </summary>");
					sb.AppendLine("			[System.ComponentModel.Description(\"Field mapping for the '" + column.PascalName + "' property\")]");
					sb.AppendLine("			" + column.PascalName + ",");
				}

				if (_currentTable.AllowCreateAudit)
				{
					sb.AppendLine("			 /// <summary>");
					sb.AppendLine("			 /// Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedByColumnName) + "' property");
					sb.AppendLine("			 /// </summary>");
					sb.AppendLine("			[System.ComponentModel.Description(\"Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedByColumnName) + "' property\")]");
					sb.AppendLine("			" + StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedByColumnName) + ",");
					sb.AppendLine("			 /// <summary>");
					sb.AppendLine("			 /// Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedDateColumnName) + "' property");
					sb.AppendLine("			 /// </summary>");
					sb.AppendLine("			[System.ComponentModel.Description(\"Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedDateColumnName) + "' property\")]");
					sb.AppendLine("			" + StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedDateColumnName) + ",");
				}

				if (_currentTable.AllowModifiedAudit)
				{
					sb.AppendLine("			 /// <summary>");
					sb.AppendLine("			 /// Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedByColumnName) + "' property");
					sb.AppendLine("			 /// </summary>");
					sb.AppendLine("			[System.ComponentModel.Description(\"Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedByColumnName) + "' property\")]");
					sb.AppendLine("			" + StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedByColumnName) + ",");
					sb.AppendLine("			 /// <summary>");
					sb.AppendLine("			 /// Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedDateColumnName) + "' property");
					sb.AppendLine("			 /// </summary>");
					sb.AppendLine("			[System.ComponentModel.Description(\"Field mapping for the '" + StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedDateColumnName) + "' property\")]");
					sb.AppendLine("			" + StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedDateColumnName) + ",");
				}

				sb.AppendLine("		}");
				sb.AppendLine();
				sb.AppendLine("		#endregion");
				sb.AppendLine();
				sb.AppendLine("		#endregion");
				sb.AppendLine();

				sb.AppendLine("		#region Constructors");
				sb.AppendLine();
				sb.AppendLine("		/// <summary>");
				sb.AppendLine("		/// The default contructor for the " + _currentTable.PascalName + " DTO");
				sb.AppendLine("		/// </summary>");
				sb.AppendLine("		public " + _currentTable.PascalName + "DTO()");
				sb.AppendLine("		{");
				sb.AppendLine("		}");
				sb.AppendLine();
				sb.AppendLine("		#endregion");
				sb.AppendLine();
				this.AppendEnum();
				sb.AppendLine("		#region Object Properties");
				sb.AppendLine();

				foreach (Column column in _currentTable.GeneratedColumns)
				{					
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// The " + column.PascalName + " field");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		[DataMember()]");
					if (_currentTable.IsColumnInherited(column))
						sb.AppendLine("		public override " + column.GetCodeType(true) + " " + column.PascalName + " { get; set; }");
					else
						sb.AppendLine("		public virtual " + column.GetCodeType(true) + " " + column.PascalName + " { get; set; }");
				}

				if (_currentTable.AllowCreateAudit)
				{
					string inheritor = (_currentTable.InheritsCreateAudit ? "override" : "virtual");
					string createdFieldName = StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedDateColumnName);
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// The " + createdFieldName + " field");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		[DataMember()]");
					sb.AppendLine("		public " + inheritor + " DateTime? " + createdFieldName + " { get; set; }");

					createdFieldName = StringHelper.DatabaseNameToPascalCase(_model.Database.CreatedByColumnName);
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// The " + createdFieldName + " field");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		[DataMember()]");
					sb.AppendLine("		public " + inheritor + " string " + createdFieldName + " { get; set; }");
				}

				if (_currentTable.AllowModifiedAudit)
				{
					string inheritor = (_currentTable.InheritsModifyAudit ? "override" : "virtual");
					string modifiedFieldName = StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedDateColumnName);
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// The " + modifiedFieldName + " field");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		[DataMember()]");
					sb.AppendLine("		public " + inheritor + " DateTime? " + modifiedFieldName + " { get; set; }");

					modifiedFieldName = StringHelper.DatabaseNameToPascalCase(_model.Database.ModifiedByColumnName);
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// The " + modifiedFieldName + " field");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		[DataMember()]");
					sb.AppendLine("		public " + inheritor + " string " + modifiedFieldName + " { get; set; }");
				}

				sb.AppendLine();
				sb.AppendLine("		#endregion");
				sb.AppendLine();
				sb.AppendLine("	}");
				sb.AppendLine();
			}
			catch (Exception ex)
			{
				throw;
			}
		}

		private void AppendEnum()
		{
			try
			{
				if (_currentTable.IsTypeTable && _currentTable.PrimaryKeyColumns.Count == 1)
				{
					sb.AppendLine("		#region StaticDataConstants Enumeration");
					sb.AppendLine("		/// <summary>");
					sb.AppendLine("		/// Enumeration to define static data items and their ids '" + _currentTable.PascalName + "' table.");
					sb.AppendLine("		/// </summary>");
					sb.AppendLine("		public enum " + _currentTable.PascalName + "Constants");
					sb.AppendLine("		{");
					foreach (RowEntry rowEntry in _currentTable.StaticData)
					{
						//ToDo: More than one column as primary key blows up
						string id = string.Empty;
						string name = string.Empty;
						string description = string.Empty;
						foreach (CellEntry cellEntry in rowEntry.CellEntries)
						{
							Column column = (Column)cellEntry.ColumnRef.Object;
							Column pk = (Column)_currentTable.PrimaryKeyColumns[0];
							if (column.Key == pk.Key)
								id = cellEntry.Value;
							if (StringHelper.Match(column.Name, "name"))
								name = ValidationHelper.MakeCodeIdenitifer(cellEntry.Value);
							if (StringHelper.Match(column.Name, "description"))
								description = cellEntry.Value;
						}

						if (string.IsNullOrEmpty(name)) name = description;
						if (description != "")
						{
							sb.AppendLine("			/// <summary>");
							sb.AppendLine("			/// " + description);
							sb.AppendLine("			/// </summary>");
							sb.AppendLine("			[Description(\"" + description + "\")]");
						}
						else
						{
							sb.AppendLine("			/// <summary>");
							sb.AppendLine("			/// Enumeration for the '" + name + "' item");
							sb.AppendLine("			/// </summary>");
							sb.AppendLine("			[Description(\"" + description + "\")]");
						}

						string key = ValidationHelper.MakeDatabaseIdentifier(name.Replace(" ", ""));
						if ((key.Length > 0) && ("0123456789".Contains(key[0])))
							key = "_" + key;

						sb.AppendLine("			" + key + " = " + id + ",");					
					}
					sb.AppendLine("		}");
					sb.AppendLine("		#endregion");
					sb.AppendLine();
				}
			}
			catch (Exception ex)
			{
				throw;
			}

		}

		#endregion


	}
}